#####################################################################################
#
# time_discrepancy.pl
#   Attempts to find discrepencies between server-side and local timestamps
#   
# References:
#   Lee Whitfield (http://forensic4cast.com/2011/07/flashpost-google-plus-artefacts-url-forwarding/) 
#   Vincent Toubiana and Helen Nissenbaum (http://repository.cmu.edu/cgi/viewcontent.cgi?article=1058&context=jpc)
#
# Plugin Author: Ryan Benson (ryan@obsidianforensics.com)
#
#####################################################################################

package time_discrepancy;
use strict;
use URI::Escape;

my %config = (friendlyName   => "Time Discrepancy Finder",
              description    => "Attempts to find discrepencies between server-side and local timestamps",
              artifactType   => "cookie,url",
              remoteLookups  => 0,
              browser        => "any",
              browserVersion => 0,
              version        => 20130903);

sub getConfig       { return %config; }
sub getFriendlyName { return $config{friendlyName}; }
sub getDescription  { return $config{description};; }
sub getArtifactType { return $config{artifactType}; }
sub getRemoteLookups{ return $config{remoteLookups}; }
sub getVersion      { return $config{version}; }

my $counter = 0;

sub pluginmain{

#               record type         cookie      website                     regex
  &parseCookie('cookie (created)', 'id',       '.doubleclick.net/',        't=(\d{10})\|');
  &parseCookie('cookie (created)', '_curtime', '.pubmatic.com/',           '(\d{10})');
  &parseCookie('cookie (created)', 'dp_rec',   '.invitemedia.com/',        ':(\d{10})}');
  &parseCookie('cookie (created)', 'AA002',    '.atdmt.com/',              '^(\d{10})-');
  &parseCookie('cookie (created)', 'mt_mop',   '.mathtag.com/',            '4:(\d{10})');
  &parseCookie('cookie (created)', '33x_ps',   '.33across.com/',           'ts%3D(\d{13})');
  &parseCookie('cookie (created)', 'guest_id', '.twitter.com/',            'v1%3A(\d{13})');
  &parseCookie('cookie (created)', 'pid',      '.twitter.com/',            'v3:(\d{13})');
  &parseCookie('cookie (created)', 'FBJSC',    'www.yahoo.com/',           '(\d{10})');
  &parseCookie('cookie (created)', 'UIDR',     '.scorecardresearch.com/',  '(\d{10})');
  &parseCookie('cookie (created)', 'put_3076', '.rubiconproject.com/',     '(\d{10})');
  &parseCookie('cookie (created)', 'mdata',    '.mookie1.com/',            '|(\d{10})$');
  &parseCookie('cookie (created)', 'PREF',     '%',                        'TM=(\d{10})');

#           record type   url                   regex
  &parseURL('url%',       '%google.%&n=%',     '&n=(\d{13})');

  ::printStatus("$counter items parsed");
}

sub parseCookie {
  my $type = shift;
  my $name = shift;
  my $site = shift;
  my $regex = shift;

  my $select_h = $::datastore->prepare(" SELECT cookies.timestamp,cookies.value,cookies.rid,cookies.derived 
                      FROM cookies, rid WHERE cookies.rid = rid.rid 
                      AND rid.record_type LIKE ? AND cookies.name LIKE ? AND cookies.url LIKE ? ");

  my $update_h = $::datastore->prepare(" UPDATE cookies SET derived=? WHERE rid=? ");

  $select_h->execute($type,$name,$site);
  while (my @row = $select_h->fetchrow) {
    my $derived = $row[3];

    # Check if this plugin has already been run; if not, run it.  
    unless ($derived=~/\[Time Discrepancy\]/){
      if ($row[1] =~ /$regex/){
        if ($1){  
          my $serverts = $1;
          if ($serverts > 9999999999){ $serverts = ($serverts/1000); }
          my $diff = $serverts - ::WebkitToEpoch($row[0]);
          $derived .= "Server-side Timestamp: " . ::EpochToHuman($serverts) . " | Local Timestamp: " . ::EpochToHuman(::WebkitToEpoch($row[0])) . " | Difference: " . &timeDiff($diff) . " [Time Discrepancy] ";  
          $counter++;  
          $update_h->execute( $derived, $row[2] );
        }
      }
    }
  }
}


sub parseURL {
  my $type = shift;
  my $url = shift;
  my $regex = shift;

  my $select_h = $::datastore->prepare(" SELECT urls.first_visit_time,urls.url,urls.rid,urls.derived 
                      FROM urls, rid WHERE urls.rid = rid.rid 
                      AND rid.record_type LIKE ? AND urls.url LIKE ? ");

  my $update_h = $::datastore->prepare(" UPDATE urls SET derived=? WHERE rid=? ");

  $select_h->execute($type,$url);
  while (my @row = $select_h->fetchrow) {
    my $derived = $row[3];

    # Check if this plugin has already been run; if not, run it.  
    unless ($derived=~/\[Time Discrepancy\]/){
      if ($row[1] =~ /$regex/){
        if ($1){
          my $serverts = $1;
          if ($serverts > 9999999999){ $serverts = ($serverts/1000); }
          my $diff = $serverts - ::WebkitToEpoch($row[0]);
          $derived .= "Server-side Timestamp: " . ::EpochToHuman($serverts) . " | Local Timestamp: " . ::EpochToHuman(::WebkitToEpoch($row[0])) . " | Difference: " . &timeDiff($diff) . " [Time Discrepancy] ";  
          $counter++;  
          $update_h->execute( $derived, $row[2] );
        }
      }
    }                   
  }
}

sub timeDiff {
  my $diff = shift;
  my $neg;
  if ($diff < 0){
    $diff = $diff*(-1); 
    $neg = 1; }
  my ($days, $hours, $min, $sec)=("",00,00,00);
  if ($diff >= 86400){
    $days = int($diff/86400);
    $diff = $diff - ($days * 86400); }
  if ($diff >= 3600){
    $hours = int($diff/3600);
    $diff = $diff - ($hours * 3600); }
  if ($diff >= 60){
    $min = int($diff/60);
    $diff = $diff - ($min * 60);  }
  $sec = $diff;

  my $output;
  ($days) ? $output = "$days:" : 0;
  $output .= sprintf("%02d",$hours) . ":" . sprintf("%02d",$min) . ":" . sprintf("%05.2f",$sec) . " (days:hh:mm:ss.ss)";
  return $output;
}

1;